package xyhoo.springframework.beans.factory.support;


import xyhoo.springframework.beans.factory.BeanDefinitionStoreException;
import xyhoo.springframework.core.env.Environment;
import xyhoo.springframework.core.env.EnvironmentCapable;
import xyhoo.springframework.core.env.StandardEnvironment;
import xyhoo.springframework.core.io.Resource;
import xyhoo.springframework.core.io.ResourceLoader;
import xyhoo.springframework.core.io.support.PathMatchingResourcePatternResolver;
import xyhoo.springframework.core.io.support.ResourcePatternResolver;
import xyhoo.springframework.util.Assert;

import java.io.IOException;
import java.util.Collections;
import java.util.Set;

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

    private ResourceLoader resourceLoader;

    private Environment environment;

    private ClassLoader beanClassLoader;

    private final BeanDefinitionRegistry registry;


    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        // Determine ResourceLoader to use.
        if (this.registry instanceof ResourceLoader _resourceLoader) {
            this.resourceLoader = _resourceLoader;
        } else {
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }

        // Inherit Environment if possible
        if (this.registry instanceof EnvironmentCapable environmentCapable) {
            this.environment = environmentCapable.getEnvironment();
        } else {
            this.environment = new StandardEnvironment();
        }
    }

    @Override
    public ResourceLoader getResourceLoader() {
        return this.resourceLoader;
    }

    @Override
    public final BeanDefinitionRegistry getRegistry() {
        return this.registry;
    }

    @Override
    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

    public Environment getEnvironment() {
        return this.environment;
    }

    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }
        if (resourceLoader instanceof ResourcePatternResolver resourcePatternResolver) {
            try {
                Resource[] resources = resourcePatternResolver.getResources(location);

                int count = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                return count;
            } catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        } else {
            Resource resource = resourceLoader.getResource(location);
            int count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            return count;
        }
    }

    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        for (Resource resource : resources) {
            count += loadBeanDefinitions(resource);
        }
        return count;
    }

}
